﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;

namespace QuailDashboard.View.Helpers
{
    public static class Mouse
    {
        private const int doubleClickInterval = 200;
        private static readonly DependencyProperty DoubleClickTimerProperty = DependencyProperty.RegisterAttached("DoubleClickTimer", typeof(DispatcherTimer), typeof(UIElement), null);
        private static readonly DependencyProperty DoubleClickHandlersProperty = DependencyProperty.RegisterAttached("DoubleClickHandlers", typeof(List<MouseButtonEventHandler>), typeof(UIElement), null);
        private static readonly DependencyProperty DoubleClickPositionProperty = DependencyProperty.RegisterAttached("DoubleClickPosition", typeof(Point), typeof(UIElement), null);

        /// <summary>
        /// Adds a double click event handler.
        /// </summary>
        /// <param name="element">The Element to listen for double clicks on.</param>
        /// <param name="handler">The handler.</param>
        public static void AddDoubleClick(this UIElement element, MouseButtonEventHandler handler)
        {
            element.MouseLeftButtonDown += Element_MouseLeftButtonDown;
            List<MouseButtonEventHandler> handlers;
            handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
            if (handlers == null)
            {
                handlers = new List<MouseButtonEventHandler>();
                element.SetValue(DoubleClickHandlersProperty, handlers);
            }

            handlers.Add(handler);
        }

        /// <summary>
        /// Removes a double click event handler.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="handler">The handler.</param>
        public static void RemoveDoubleClick(this UIElement element, MouseButtonEventHandler handler)
        {
            element.MouseLeftButtonDown -= Element_MouseLeftButtonDown;
            List<MouseButtonEventHandler> handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
            if (handlers != null)
            {
                handlers.Remove(handler);
                if (handlers.Count == 0)
                    element.ClearValue(DoubleClickHandlersProperty);
            }
        }

        private static void Element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            UIElement element = sender as UIElement;
            Point position = e.GetPosition(element);
            DispatcherTimer timer = element.GetValue(DoubleClickTimerProperty) as DispatcherTimer;

            if (timer != null) 
            {
                // DblClick
                timer.Stop();
                Point oldPosition = (Point)element.GetValue(DoubleClickPositionProperty);
                element.ClearValue(DoubleClickTimerProperty);
                element.ClearValue(DoubleClickPositionProperty);

                // mouse didn't move => Valid double click
                if (Math.Abs(oldPosition.X - position.X) < 1 && Math.Abs(oldPosition.Y - position.Y) < 1)
                {
                    List<MouseButtonEventHandler> handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
                    if (handlers != null)
                    {
                        foreach (MouseButtonEventHandler handler in handlers)
                        {
                            handler(sender, e);
                        }
                    }

                    return;
                }
            }

            // First click or mouse moved. Start a new timer
            timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(doubleClickInterval) };
            timer.Tick += (s, args) =>
            {  
                // DblClick timed out
                ((DispatcherTimer)s).Stop();
                element.ClearValue(DoubleClickTimerProperty); // clear timer
                element.ClearValue(DoubleClickPositionProperty); // clear first click position
            };
            element.SetValue(DoubleClickTimerProperty, timer);
            element.SetValue(DoubleClickPositionProperty, position);
            timer.Start();
        }
    }
}